/**
  ******************************************************************************
  * @file 
  * @brief 
  * @author Moon
  * @version V1.0.0
  * @date 2022/09/18
  ******************************************************************************
  */

 /* Includes ------------------------------------------------------------------*/
#include "drv_f4_can.h"

/* Private defines -----------------------------------------------------------*/
/* Private Struct  -----------------------------------------------------------*/
typedef struct
{
	uint32_t BaudRate;  //CAN波特率
    uint32_t Fpclk;     //CAN时钟频率
    uint8_t tsjw;       //重新同步跳跃时间单元
    uint8_t tbs1;       //时间段2的时间单元
    uint8_t tbs2;       //时间段1的时间单元
    uint16_t brp;       //波特率分频器
} can_param_t;

typedef void (*CanCallBack)(uint32_t id, uint8_t *buf, uint32_t len);
/* Private enum    -----------------------------------------------------------*/
enum
{
    B1M_F42M = 0,           //波特率1M，can时钟42M
    BXM_FXM_NUM,
};

can_param_t can_param[BXM_FXM_NUM] = 
{
    [B1M_F42M] = 
    {
        .BaudRate = 1000000, 
        .Fpclk = 42000000, 
        .tsjw = CAN_SJW_1tq, 
        .tbs1 = CAN_BS2_2tq, 
        .tbs2 = CAN_BS1_3tq, 
        .brp = 7
    },
};

drv_can_t *can1cb;
drv_can_t *can2cb;
/* Private Variable  ---------------------------------------------------------*/
/***********************************************************************************
 * @brief  查找对应参数
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
uint16_t find_param(drv_can_t *this)
{
    uint16_t i = 0;

    if (this == NULL)
        return 0;

    for (i = 0; i < BXM_FXM_NUM; i++)
    {
        if ((this->baut == can_param[i].BaudRate) &&
            (this->clk == can_param[i].Fpclk))
            return i;
    }
    return 0;
}

/***********************************************************************************
 * @brief   can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)	
 * ex:      len:数据长度(最大为8)
stm32f103查询can发送邮箱 * @par      
 * None
 * @retval void None
 **********************************************************************************/
uint8_t CanSendMsg(drv_can_t *this, uint8_t len, CanTxMsg *TxMessage)
{
	uint8_t mbox;
	uint16_t i = 0;

	TxMessage->DLC = len; // 要发送的数据长度
    do{
        mbox = CAN_Transmit(this->private.pcan, TxMessage);
    }
    while (mbox == CAN_TxStatus_NoMailBox);
    while ((i < 0XFFF))
    {
        if (CAN_TransmitStatus(CAN1, mbox) == CAN_TxStatus_Ok)
        {
            break;
        }
        i++;
    }

    // while ((CAN_TransmitStatus(this->private.pcan, mbox) == CAN_TxStatus_Failed) && (i < 0XFFF))
	// 	i++; //等待发送结束
	// if (i >= 0XFFF)
	// 	return 1;
	return 0;
}
/***********************************************************************************
 * @brief   CAN发送
 * ex:      
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
void _CAN_tx(drv_can_t *this, uint32_t targe_id, uint8_t *_buf, uint32_t len)
{
	int package_num;
	int i = 0, j = 0;
    CanTxMsg TxMessage;
    
	TxMessage.StdId = (targe_id & 0x7FF);			// 标准标识符为0
	TxMessage.ExtId = (targe_id & 0x1FFFFFFF); // 设置扩展标示符（29位）
    if (this->type == CAN_STD)
	    TxMessage.IDE = CAN_Id_Standard;     // 标准帧
    else
        TxMessage.IDE = CAN_Id_Extended;     // 扩展帧
	TxMessage.RTR = CAN_RTR_Data;		 // 数据帧
	package_num = len / 8;

	for (j = 0; j < package_num; j++)
	{
		for (i = 0; i < 8; i++)
		{
			TxMessage.Data[i] = _buf[i + j * 8];
		}
		CanSendMsg(this, 8, &TxMessage);
	}
	if (len - package_num * 8 != 0)
	{
		for (i = 0; i < len - package_num * 8; i++)
		{
			TxMessage.Data[i] = _buf[i + j * 8];
		}
		CanSendMsg(this, len - package_num * 8, &TxMessage);
	}
}

/***********************************************************************************
 * @brief   can初始化
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
int Drv_Can_Init(drv_can_t *this)
{
    uint8_t irq;
    uint16_t index;
    uint8_t afconfig;
	CAN_InitTypeDef CAN_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
	CAN_FilterInitTypeDef CAN_FilterInitStructure;

    if (this == NULL)
        return -1;
    
    this->Send = _CAN_tx;
    if (strcmp(this->DRV, "CAN1") == 0)
    {
        irq = CAN1_RX0_IRQn;
        afconfig = GPIO_AF_CAN1;
        this->private.pcan = CAN1;
        can1cb = this;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    }  
    else if (strcmp(this->DRV, "CAN2") == 0)
    {
        irq = CAN2_RX0_IRQn;
        afconfig = GPIO_AF_CAN2;
        this->private.pcan = CAN2;
        can2cb = this;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);
    }
    else
        return -1;
    //  TX IO
    if(Common_Gpio_AFConfig(this->Tx_Pin, afconfig, GPIO_PuPd_UP) < 0){
        return -1;
    }

    //  RX IO
    if(Common_Gpio_AFConfig(this->Rx_Pin, afconfig, GPIO_PuPd_UP) < 0){
        return -1;
    }        
    
    index = find_param(this);
	//CAN单元设置
	CAN_InitStructure.CAN_TTCM = DISABLE; //非时间触发通信模式
	CAN_InitStructure.CAN_ABOM = DISABLE; //软件自动离线管理
	CAN_InitStructure.CAN_AWUM = DISABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
	CAN_InitStructure.CAN_NART = ENABLE;  //开启报文自动传送
	CAN_InitStructure.CAN_RFLM = DISABLE; //报文不锁定,新的覆盖旧的
	CAN_InitStructure.CAN_TXFP = DISABLE; //优先级由报文标识符决定
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;		//模式设置： mode:0,普通模式;1,回环模式;
	//设置波特率
	CAN_InitStructure.CAN_SJW = can_param[index].tsjw;			 //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位  CAN_SJW_1tq	 CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
	CAN_InitStructure.CAN_BS1 = can_param[index].tbs1;			 //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
	CAN_InitStructure.CAN_BS2 = can_param[index].tbs2;			 //Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~	CAN_BS2_8tq
	CAN_InitStructure.CAN_Prescaler = can_param[index].brp;      //分频系数(Fdiv)为brp
	CAN_Init(this->private.pcan, &CAN_InitStructure);		     //初始化CAN1

    /*拓展帧ID格式：0x0000 + 一字节目标id + 一字节源id
      所以帧滤波器：0x0000 +   本节点id   +  0x00
      帧滤波器掩码：0x1fff +     0xff     + 0x00*/
    uint32_t frame_id   = (uint32_t)this->CANID;
    uint32_t frame_mack = this->mack;
    
	CAN_FilterInitStructure.CAN_FilterNumber = 0;																			//过滤器0
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;															//屏蔽位模式
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;														//32位宽

    if (this->type == CAN_STD)
    {
        CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)frame_id << 21) & 0xffff0000) >> 16; // 32位ID
        CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)frame_id << 21) | CAN_ID_STD) & 0xffff;
    }
    else
    {
        CAN_FilterInitStructure.CAN_FilterIdHigh = (uint16_t)((frame_id << 3) >> 16);
        CAN_FilterInitStructure.CAN_FilterIdLow = (uint16_t)((frame_id << 3) | CAN_ID_EXT);
    }

    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (uint16_t)((frame_mack << 3) >> 16);
	CAN_FilterInitStructure.CAN_FilterMaskIdLow  = (uint16_t)((frame_mack << 3));
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //过滤器0关联到FIFO0
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;							 //激活过滤器0

	CAN_FilterInit(&CAN_FilterInitStructure); //滤波器初始化
	CAN_ITConfig(this->private.pcan, CAN_IT_FMP0, ENABLE); //FIFO0消息挂号中断允许.    

    /* 设置中断并打开时钟 */
    NVIC_InitStructure.NVIC_IRQChannel                      = irq;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = this->Rx_Priority;      
    NVIC_InitStructure.NVIC_IRQChannelSubPriority           = 0;       
    NVIC_InitStructure.NVIC_IRQChannelCmd                   = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    return 0;
}


/***********************************************************************************
 * @brief   CAN接收中断服务程序
 * ex:      
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
void CAN1_RX0_IRQHandler(void)
{
    CanRxMsg RxMessage;

	if (CAN_MessagePending(CAN1, CAN_FIFO0) == 0)
	{
		return;
	}

	CAN_Receive(CAN1, CAN_FIFO0, &RxMessage); //接收FIFO0中的数据

	//将原始数据传送至缓存并通知任务处理
	if (can1cb != NULL)
    {
        if (can1cb->type == CAN_STD)
            can1cb->RxCallBack(RxMessage.StdId, RxMessage.Data, RxMessage.DLC);
        else
            can1cb->RxCallBack(RxMessage.ExtId, RxMessage.Data, RxMessage.DLC);
    }
}

/***********************************************************************************
 * @brief   CAN接收中断服务程序
 * ex:      
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
void CAN2_RX0_IRQHandler(void)
{
    CanRxMsg RxMessage;

	if (CAN_MessagePending(CAN2, CAN_FIFO0) == 0)
	{
		return;
	}

	CAN_Receive(CAN2, CAN_FIFO0, &RxMessage); //接收FIFO0中的数据

	//将原始数据传送至缓存并通知任务处理
	if (can2cb != NULL)
    {
        if (can2cb->type == CAN_STD)
            can2cb->RxCallBack(RxMessage.StdId, RxMessage.Data, RxMessage.DLC);
        else
            can2cb->RxCallBack(RxMessage.ExtId, RxMessage.Data, RxMessage.DLC);
    }
}
